package com.leyou.gateway.filter;

import com.leyou.common.auth.pojo.Payload;
import com.leyou.common.auth.pojo.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.constants.LyConstants;
import com.leyou.gateway.config.FilterProperties;
import com.leyou.gateway.config.JwtProperties;
import com.leyou.gateway.scheduler.AppTokenScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 权限过滤器
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Autowired
    private JwtProperties jwtProps;

    @Autowired
    private FilterProperties filterProps;

    @Autowired
    private AppTokenScheduler appTokenScheduler;


    /**
     * 编写过滤逻辑
     * @param exchange： 封装了request和response对象
     * @param chain 过滤器链，控制过滤器的流程。用于执行后面的过滤器或者执行目标资源
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //exchange： 封装了request和response对象的
        //ServerHttpRequest是对HttpServletRequest对象的二次封装
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //往请求头添加服务token
        // 参数一:服务认证请求头 请求头一定要是“APP_TOKEN_HEADER”吗？可以随意定
        // 参数二:Token
        request.mutate().header(LyConstants.APP_TOKEN_HEADER,appTokenScheduler.getAppToken());

        //加入白名单判断
        //1.获取当前访问的URL路径
        String uri = request.getURI().getPath(); // 如： /api/item/category/of/parent

        //2.判断当前访问路径是否在白名单列表中
        List<String> allowPaths = filterProps.getAllowPaths();
        for(String allowPath:allowPaths){ // /api/item
            if(uri.contains(allowPath)){
                // String的contains方法查看allowPath字符串是否是uri字符串的字串
                //3.如果在，直接放行了
                return chain.filter(exchange);
            }
        }
        Map<Object,Object> map = new ConcurrentHashMap<>();

        //2.校验用户token是否合法（是否可以使用公钥解析）
        Payload<UserInfo> payload = null;

        try {
            //1.从请求中获取Cookie的用户token
            //getCookies(): 取出所有Cookie
            //getFirst(): 取出指定名称的第一个Cookie
            //getValue(): 取出Cookie的值
            String token = request.getCookies().getFirst(jwtProps.getCookie().getCookieName()).getValue();
            payload = JwtUtils.getInfoFromToken(token,jwtProps.getPublicKey(), UserInfo.class);
        } catch (Exception e) {
            //throw new LyException(ExceptionEnum.UNAUTHORIZED);
            //返回401状态码
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //中止请求
            return response.setComplete();
        }

        //TODO 查询RBAC表获取当前用户拥有的权限，根据权限判断是否可以访问当前资源

        //放行请求
        return chain.filter(exchange);
    }

    /**
     * 配置过滤器的顺序
     *   返回的数字越大，优先级越小
     *     建议不要写10000以后的值
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}
